package org.marverse.scripting

import ScriptingUtil._

/**
 * Unchecked version of {@link ConditionExpr}. Checkes whether {@link condition} results in a {@link TruthType}.
 */
trait UncheckedConditionalExpr extends UncheckedExpression {
  /**
   * The condition that decides the evaluation of this expression.
   */
  val condition: UncheckedExpression
  /**
   * The expression that is evaluated if the evaluation of {@link condition} return <code>true</code>.
   */
  val success: UncheckedExpression
  /**
   * The expression that is evaluated if the evaluation of {@link condition} return <code>true</code>.
   */
  val failure: UncheckedExpression
}

object UncheckedConditionalExpr {
  /**
   * Returns a {@link UncheckedConditionalExpr} with the given subexpressions.
   */
  def apply(condition: UncheckedExpression, success: UncheckedExpression, failure: UncheckedExpression): UncheckedConditionalExpr =
    new UncheckedConditionalExprImpl(condition, success, failure)
}

/**
 * Expression that evaluates on of two different expressions depending on a 
 * condition expression. 
 */
trait ConditionalExpr extends Expression {
  /**
   * The condition that decides the evaluation of this expression.
   */
  val condition: Expression
  /**
   * The expression that is evaluated if the evaluation of {@link condition} return <code>true</code>.
   */
  val success: Expression
  /**
   * The expression that is evaluated if the evaluation of {@link condition} return <code>false</code>.
   */
  val failure: Expression
}

final private class UncheckedConditionalExprImpl(val condition: UncheckedExpression, val success: UncheckedExpression, val failure: UncheckedExpression)
extends UncheckedConditionalExpr {
  
  def childUncheckedExpressions = Seq(condition, success, failure)
  def checked(implicit ctx: MutableTypedMap[TypedKey, Any]) = {
    val c = condition.checked
    if (c.expressionType >:: TruthType)
      TypeErrorExpr(c, TruthType)
    else
      new ConditionalExprImpl(c, success.checked, failure.checked)
  }
  
}

final private class ConditionalExprImpl(val condition: Expression, val success: Expression, val failure: Expression)
extends ConditionalExpr {
  
  override def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
    super.check
    assertThat(condition.expressionType <=:: TruthType,
      "ConditionalExpr: condition (%s) expressionType (%s) <=:: TruthType".format(condition, condition.expressionType))
  }
  
  def childExpressions = Seq(condition, success, failure)
  def expressionType(implicit ctx: MutableTypedMap[TypedKey, Any]) = {
    val st = success.expressionType
    val ft = failure.expressionType
    if (st >=:: ft) st 
    else if (ft >=:: st) ft
    else AnyType
  }
  def evaluate(implicit ctx: MutableTypedMap[TypedKey, Any]) = 
    if (condition.evaluate.asInstanceOf[Boolean])
      success.evaluate
    else
      failure.evaluate
  
}
